#include "VectorNd.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>

static inline ValueType vectorNd_dot_impl(VectorNd* a, VectorNd* b);

static inline ValueType vectorNd_dot_impl(VectorNd* a, VectorNd* b)
{
	ValueType dot = 0;
	for (int i = 0; i < a->size; ++i)
		dot += a->data[i] * b->data[i];
	return dot;
}


VectorNd* vectorNd_create(int n, ValueType d[])
{
	VectorNd* v = (VectorNd*)malloc(sizeof(VectorNd));
	assert(v);
	v->size = n;
	for (int i = 0; i < n; ++i)
		v->data[i] = d[i];
	return v;
}

VectorNd* vectorNd_free(VectorNd* vector)
{
	if (vector) {
		free(vector->data);
		free(vector);
	}
	return NULL;
}

VectorNd* vectorNd_copy(VectorNd* dest, VectorNd* src)
{
	assert(dest && src);
	assert(dest->size == src->size);
	memcpy(dest->data, src->data, sizeof(ValueType) * dest->size);
	return dest;
}

VectorNd* vectorNd_add(VectorNd* a, VectorNd* b, VectorNd* c)
{
	assert(a && b && c);
	assert(a->size == b->size);
	assert(b->size > 0);
	if (c != a)
		vectorNd_copy(c, a);
	for (int i = 0; i < c->size; ++i)
		c->data[i] += b->data[i];
	return c;
}

VectorNd* vectorNd_sub(VectorNd* a, VectorNd* b, VectorNd* c)
{
	assert(a && b && c);
	assert(a->size == b->size);
	assert(b->size > 0);
	if (c != a)
		vectorNd_copy(c, a);
	for (int i = 0; i < c->size; ++i)
		c->data[i] -= b->data[i];
	return c;
}

VectorNd* vectorNd_mul_scalar(VectorNd* a, ValueType k, VectorNd* b)
{
	assert(a && b);
	assert(a->size > 0);
	if (a != b)
		vectorNd_copy(b, a);
	for (int i = 0; i < b->size; ++i)
		b->data[i] *= k;
	return b;
}

ValueType vectorNd_dot(VectorNd* a, VectorNd* b)
{
	assert(a && b);
	assert(a->size == b->size);
	assert(b->size > 0);
	return vectorNd_dot_impl(a, b);
}

ValueType vectorNd_cross(VectorNd* a, VectorNd* b)
{
	assert(a && b);
	assert(a->size == b->size);
	assert(b->size > 0);
	return a->data[0] * b->data[1] - a->data[1] * b->data[0];
}

ValueType vectorNd_norm(VectorNd* a)
{
	assert(a);
	assert(a->size > 0);
	ValueType norm = vectorNd_dot_impl(a, a);
	return sqrt(norm);
}

VectorNd* vectorNd_normalize(VectorNd* a)
{
	assert(a);
	assert(a->size > 0);
	ValueType norm = vectorNd_norm(a);
	if (norm>0)
		for (int i = 0; i < a->size; ++i)
			a->data[i] /= norm;
	return a;
}

/*

*/